<?php

namespace app;

use Throwable;
use think\Response;
use think\exception\Handle;
use think\response\Redirect;
use app\exception\AuthException;
use app\exception\LogicException;
use think\exception\HttpException;
use app\exception\NotFoundException;
use think\exception\ValidateException;
use app\exception\LogicValidateException;
use think\exception\HttpResponseException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;

/**
 * 应用异常处理类
 */
class ExceptionHandle extends Handle
{
    /**
     * 不需要记录信息（日志）的异常类列表
     * @var array
     */
    protected $ignoreReport = [
        HttpException::class,
        HttpResponseException::class,
        ModelNotFoundException::class,
        DataNotFoundException::class,
        ValidateException::class,
    ];

    /**
     * 记录异常信息（包括日志或者其它方式记录）
     *
     * @access public
     * @param Throwable $exception
     * @return void
     */
    public function report(Throwable $exception): void
    {
        // 使用内置的方式记录异常日志
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @access public
     * @param \think\Request $request
     * @param Throwable $e
     * @return Response
     */
    public function render($request, Throwable $e): Response
    {
        if (
            ($e instanceof LogicException || $e instanceof AuthException ||
            $e instanceof DataNotFoundException || $e instanceof ModelNotFoundException ||
            $e instanceof ValidateException
        )) {
            // 显示错误信息
            $this->app->config->set(['show_error_msg' => true], 'app');

            return $this->renderForLogic($request, $e);
        }

        // 其他错误交给系统处理
        return parent::render($request, $e);
    }

    /**
     * 业务逻辑异常处理
     *
     * @param $request
     * @param $e
     * @return Response|Redirect
     */
    public function renderForLogic($request, $e)
    {
        $this->isJson = $request->isJson();
        if ($e instanceof ValidateException) {
            $e = new LogicValidateException($e->getMessage());
        }
        if ($e instanceof DataNotFoundException || $e instanceof ModelNotFoundException) {
            $e = new NotFoundException(lang('communal.data Not Found'));
        }
        if ($e instanceof AuthException) {
            return $this->renderAuthException($request, $e);
        } else {
            return $this->convertLogicExceptionToResponse($e);
        }
    }

    /**
     * 授权登录异常处理
     *
     * @param \think\Request $request
     * @param $e
     * @return Response|Redirect
     */
    public function renderAuthException(\think\Request $request, $e)
    {
        if (!$this->isJson && 'b' === substr($request->rule()->getName(), 0, 1)) {
            return redirect('/b/site/view.html');
        } else {
            return $this->convertLogicExceptionToResponse($e);
        }
    }

    /**
     * 转换逻辑异常
     *
     * @access protected
     * @param Throwable $exception
     * @return Response
     */
    protected function convertLogicExceptionToResponse(Throwable $exception): Response
    {
        if (!$this->isJson) {
            $response = Response::create($this->renderExceptionContent($exception));
        } else {
            $response = Response::create($this->convertExceptionToArray($exception), 'json');
        }

        if ($exception instanceof HttpException) {
            $statusCode = $exception->getStatusCode();
            $response->header($exception->getHeaders());
        }

        return $response->code($statusCode ?? 200);
    }
}
